package com.beiding.my.common;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Component
public class QuoteCenter implements InitializingBean {

    @Autowired(required = false)
    private List<JpaRepository> quoteDaos;

    private Map<String, JpaRepository> quoeDaoMap = new HashMap<>();

    //be实体的dao
    private Map<String, JpaRepository> beDaoMap = new HashMap<>();

    private Quote getQuote(Bo holder, Bo target, String holderId, String selfId, String field) {

        Class<? extends Quote> clz = Cache.computeIfAbsent(() -> {
            try {
                Class beType = BoVoBe.getBeTypeFromBoType(target.getClass());
                return (Class<? extends Quote>) Class.forName(beType.getPackage().getName() + "._Quote_" + beType.getSimpleName());
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }, "QuoteCenter.getQuote", holder, target);

        try {
            Field[] ks = Cache.computeIfAbsent(() -> {
                try {
                    Class beType = BoVoBe.getBeTypeFromBoType(holder.getClass());
                    Field[] r = new Field[2];
                    r[0] = clz.getDeclaredField("_" + beType.getSimpleName() + "_" + field);
                    r[0].setAccessible(true);
                    r[1] = clz.getDeclaredField("self");
                    r[1].setAccessible(true);

                    return r;
                } catch (NoSuchFieldException e) {
                    throw new RuntimeException(e);
                }

            }, "QuoteCenter.getQuote.getField", clz);

            Quote r = clz.newInstance();
            r.setSelf(target.getId());
            ks[0].set(r, holderId);
            ks[1].set(r, selfId);
            return r;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    //自身的id
    @Transactional
    public boolean attach(Bo holder, Bo target, String field) {

        if (holder.getId() == null) {
            throw new RuntimeException("未指定id:" + holder.getClass().getName());
        }

        if (target.getId() == null) {
            throw new RuntimeException("未指定id:" + target.getClass().getName());
        }

        String typeName = BoVoBe.getBeTypeFromBoType(target.getClass()).getSimpleName();
        JpaRepository tj = beDaoMap.get(typeName);
        JpaRepository hj = beDaoMap.get(BoVoBe.getBeTypeFromBoType(target.getClass()).getSimpleName());

        if (!tj.existsById(target.getId()) || hj.existsById(holder.getId())) {
            return false;
        }

        JpaRepository<Quote, Long> repository = quoeDaoMap.get(typeName);
        Quote quote = getQuote(holder, target, holder.getId(), target.getId(), field);
        Optional<Quote> one = repository.findOne(Example.of(quote));
        if (!one.isPresent()) {
            repository.save(quote);
        }
        return true;
    }

    @Transactional
    public void detach(Bo holder, Bo target, String field) {
        if (holder.getId() == null) {
            throw new RuntimeException("未指定id:" + holder.getClass().getName());
        }

        if (target.getId() == null) {
            throw new RuntimeException("未指定id:" + target.getClass().getName());
        }
        JpaRepository<Quote, Long> repository = quoeDaoMap.get(BoVoBe.getBeTypeFromBoType(target.getClass()).getSimpleName());
        Quote quote = getQuote(holder, target, holder.getId(), target.getId(), field);
        Optional<Quote> one = repository.findOne(Example.of(quote));
        one.ifPresent(quote1 -> repository.deleteById(quote1.getId()));
    }

    @Override
    public void afterPropertiesSet() {
        if (quoteDaos != null) {
            for (JpaRepository qd : quoteDaos) {
                Class<?>[] interfaces = qd.getClass().getInterfaces();
                for (Class<?> anInterface : interfaces) {
                    if (anInterface.isInterface()) {
                        AnnotatedType[] annotatedInterfaces = anInterface.getAnnotatedInterfaces();
                        for (AnnotatedType annotatedInterface : annotatedInterfaces) {
                            //  System.out.println(annotatedInterface);
                            //System.out.println(annotatedInterface.getType());
                            //System.out.println(annotatedInterface.getType().getClass());
                            Type type = annotatedInterface.getType();
                            if (type instanceof ParameterizedType) {
                                ParameterizedType parameterizedType = (ParameterizedType) type;
                                if (parameterizedType.getRawType() == JpaRepository.class) {
                                    Class clz = (Class) parameterizedType.getActualTypeArguments()[0];
                                    String simpleName = clz.getSimpleName();
                                    if (simpleName.startsWith("_Quote_")) {
                                        quoeDaoMap.put(simpleName.substring(7), qd);
                                    } else {
                                        beDaoMap.put(simpleName, qd);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }


}
